package com.bzkj.inventory.utils;

import com.bzkj.inventory.domain.InventoryDiscrepancyDetail;
import com.bzkj.inventory.domain.vo.NccInventory;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ClassName InventoryCompareUtil
 * @Description TODO
 * @Author C1309
 * @Date 2025/5/14 9:58
 */
public class InventoryCompareUtil {

    // 所有需要对比的库存状态字段（key: 字段名, value: 中文名）
    private static final Map<String, String> STATUS_FIELD_MAP = new LinkedHashMap<>();

    static {
        STATUS_FIELD_MAP.put("qualifiedNum", "合格");
        STATUS_FIELD_MAP.put("unqualifiedNum", "不合格");
        STATUS_FIELD_MAP.put("quarantineNum", "待验");
        STATUS_FIELD_MAP.put("limitQualifiedNum", "限制合格");
        STATUS_FIELD_MAP.put("skunNoStateNum", "无库存状态");
        STATUS_FIELD_MAP.put("researchNum", "研究用");
        STATUS_FIELD_MAP.put("qualifiedNoUseNum", "合格不予上市");
        STATUS_FIELD_MAP.put("pendingNum", "待处理");
    }

    /**
     * 比对两个库存列表，输出库存差异明细列表
     *
     * @param nccList ERP库存数据
     * @param wmsList WMS库存数据
     * @param taskId  归属的比对任务ID
     * @return 差异明细列表
     */
    public static List<InventoryDiscrepancyDetail> compare(List<NccInventory> nccList, List<NccInventory> wmsList, Long taskId) {
        List<InventoryDiscrepancyDetail> details = new ArrayList<>();

        Map<String, NccInventory> nccMap = nccList.stream().collect(Collectors.toMap(InventoryCompareUtil::buildKey, Function.identity(), (a, b) -> a));

        Map<String, NccInventory> wmsMap = wmsList.stream().collect(Collectors.toMap(InventoryCompareUtil::buildKey, Function.identity(), (a, b) -> a));

        // WMS存在，但NCC没有的数据
        for (String key : wmsMap.keySet()) {
            if (!nccMap.containsKey(key)) {
                NccInventory wms = wmsMap.get(key);
                STATUS_FIELD_MAP.forEach((field, name) -> {
                    BigDecimal wmsQty = getQtyByField(wms, field);
                    if (!wmsQty.equals(new BigDecimal("0.0000"))) {
                        details.add(buildDiscrepancyDetail(taskId, wms, null, field, name, wmsQty, new BigDecimal(0), "WMS_ONLY"));
                    }
                });
            }
        }

        // NCC存在，但WMS没有的数据
        for (String key : nccMap.keySet()) {
            if (!wmsMap.containsKey(key)) {
                NccInventory ncc = nccMap.get(key);
                STATUS_FIELD_MAP.forEach((field, name) -> {
                    BigDecimal nccQty = getQtyByField(ncc, field);
                    if (!nccQty.equals(new BigDecimal("0.0000"))) {
                        details.add(buildDiscrepancyDetail(taskId, null, ncc, field, name, new BigDecimal(0), nccQty, "NCC_ONLY"));
                    }
                });
            }
        }

        // 都存在但库存有差异的数据
        for (String key : wmsMap.keySet()) {
            if (nccMap.containsKey(key)) {
                NccInventory wms = wmsMap.get(key);
                NccInventory ncc = nccMap.get(key);

                STATUS_FIELD_MAP.forEach((field, name) -> {
                    BigDecimal wmsQty = getQtyByField(wms, field);
                    BigDecimal nccQty = getQtyByField(ncc, field);
                    if (!equals(wmsQty, nccQty)) {
                        details.add(buildDiscrepancyDetail(taskId, wms, ncc, field, name, wmsQty, nccQty, "QUANTITY_DIFF"));
                    }
                });
            }
        }

        return details;
    }

    /**
     * 获取唯一键
     */
    private static String buildKey(NccInventory inv) {
        return String.join("_", String.valueOf(inv.getPkMaterial() == null ? "" : inv.getPkMaterial()),
                String.valueOf(inv.getPkBatchCode() == null ? "" : inv.getPkBatchCode()),
                String.valueOf(inv.getVbatchcode() == null ? "" : inv.getVbatchcode()),
                String.valueOf(inv.getCproductorid() == null ? "" : inv.getCproductorid()));
    }

    /**
     * 使用反射获取指定字段的数量值
     */
    private static BigDecimal getQtyByField(NccInventory inv, String fieldName) {
        try {
            Field field = NccInventory.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            Object val = field.get(inv);
            return val != null ? new BigDecimal(String.valueOf(val)).setScale(4, RoundingMode.HALF_UP) : new BigDecimal(0);
        } catch (Exception e) {
            return new BigDecimal("0.0000");
        }
    }

    /**
     * 比较两个浮点数是否相等（BigDecimal防误差）
     */
    private static boolean equals(BigDecimal a, BigDecimal b) {
        return a.compareTo(b) == 0;
    }

    /**
     * 构建差异明细对象
     */
    private static InventoryDiscrepancyDetail buildDiscrepancyDetail(Long taskId, NccInventory wms, NccInventory ncc, String field, String statusName, BigDecimal wmsQty, BigDecimal nccQty, String type) {
        InventoryDiscrepancyDetail d = new InventoryDiscrepancyDetail();
        d.setTaskId(taskId);
        d.setPkMaterial(wms != null ? wms.getPkMaterial() : ncc.getPkMaterial());
        d.setPkBatchCode(wms != null ? wms.getPkBatchCode() : ncc.getPkBatchCode());
        d.setVbatchcode(wms != null ? wms.getVbatchcode() : ncc.getVbatchcode());
        d.setCproductorid(wms != null ? wms.getCproductorid() : ncc.getCproductorid());
        d.setInventoryStatus(statusName);
        d.setWmsQty(wmsQty.toString());
        d.setNccQty(nccQty.toString());
        d.setDiscrepancyType(type);
        d.setResolved(false);
        d.setCreateTime(new Date());
        d.setRemark("状态[" + statusName + "]数量差异");
        return d;
    }
}

